/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#ifndef MOE_ASSIGN_POINTER_HPP
#define MOE_ASSIGN_POINTER_HPP

#include "AssignProxy.hpp"
#include "../ObjectTypeManager.h"
#include "../RawByteVector.h"

namespace MOE
{

namespace Assign
{

namespace Functors
{

template <class T, class FieldType>
struct PointerGet
{
	PointerGet(FieldType* T::* field)
		: _fieldAddr(field)
	{
	}

	void operator() (void* object, void* pData)
	{
		*static_cast<FieldType**>(pData) = static_cast<T*>(object)->*_fieldAddr;
	}

private:
	FieldType* T::* _fieldAddr;
};

template <class T, class FieldType>
struct PointerSet
{
	PointerSet(FieldType* T::* field)
		: _fieldAddr(field)
	{
	}

	void operator() (void* object, const void* pData)
	{
		static_cast<T*>(object)->*_fieldAddr = *static_cast<FieldType* const*>(pData);
	}

private:
	FieldType* T::* _fieldAddr;
};

template <class T, class FieldType>
struct PointerAccess
{
	PointerAccess(FieldType* T::* field)
		: _fieldAddr(field)
	{
	}

	void* operator() (void* object)
	{
		return &(static_cast<T*>(object)->*_fieldAddr);
	}

private:
	FieldType* T::* _fieldAddr;
};

}

// TODO: support different types of pointers (smart pointers).

template <class T, class FieldType>
AssignProxy Pointer(const RawByteVector& name, FieldType* T::* field)
{
	return AssignProxy(
		name,
		DataMemberMeta(ObjectTypeManager::GetClassID<FieldType>(), DT_Pointer)
			.DefineGetter(Functors::PointerGet<T, FieldType>(field))
			.DefineSetter(Functors::PointerSet<T, FieldType>(field))
			.DefineDirectAccessor(Functors::PointerAccess<T, FieldType>(field))
		);
}

}

}

#endif
